import { Map } from "common/types";
import * as geom from "common/geom";
import * as mvc from "common/mvc";
import * as dec from "common/decorator";

import * as dbtps from "../types";
import { Item } from "./item";
import { Texture } from "./texture";

export class UserData extends mvc.Model {
    public ints: number[] = [];
    public floats: number[] = [];
    public strings: number[] = [];
}

export class Action {

}

export class Armature extends Item {
    // 普通输出属性。
    // ==========================================================================================
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.ArmatureTypeChange)
    @dec.getterSetter(true, true)
    public type: dbtps.ArmatureType = dbtps.ArmatureType.Armature;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.ArmatureFrameRateChange)
    @dec.getterSetter(true, true)
    public frameRate: number = 24;

    @dec.getterSetter(true, false)
    public aabb: geom.Rectangle = new geom.Rectangle();
    @dec.getterSetter(true, true)
    public bones: Bone[] = [];
    @dec.getterSetter(true, true)
    public slots: Slot[] = [];
    @dec.getterSetter(true, false)
    public meshs: Mesh[] = [];
    @dec.getterSetter(true, false)
    public skins: Skin[] = [];
    @dec.getterSetter(true, false)
    public animations: Animation[] = [];
    @dec.getterSetter(true, false)
    public actions: Action[] = [];
    public userData: UserData | null = null;

    public addBone(value: Bone): void {
        console.assert(this.bones.indexOf(value) < 0);
    }

    public removeBone(value: Bone): void {
    }

    public addSlot(value: Slot): void {
        console.assert(this.slots.indexOf(value) < 0);
    }

    public removeSlot(value: Slot): void {
    }

    public addMesh(value: Mesh): void {
        console.assert(this.meshs.indexOf(value) < 0);
    }

    public removeMesh(value: Mesh): void {
    }

    public addSkin(value: Skin): void {
        console.assert(this.skins.indexOf(value) < 0);
    }

    public removeSkin(value: Skin): void {

    }

    public addAnimation(value: Animation): void {
        console.assert(this.animations.indexOf(value) < 0);
    }

    public removeAnimation(value: Animation): void {

    }
}

export class Bone extends mvc.Model implements dbtps.IName {
    // 普通输出属性。
    // ==========================================================================================
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneInheritChange)
    @dec.getterSetter(true, true)
    public inheritTranslation: boolean = true;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneInheritChange)
    @dec.getterSetter(true, true)
    public inheritRotation: boolean = true;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneInheritChange)
    @dec.getterSetter(true, true)
    public inheritScale: boolean = true;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneInheritChange)
    @dec.getterSetter(true, true)
    public inheritReflection: boolean = true;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneLengthChange)
    @dec.getterSetter(true, true)
    public length: number = 0.0;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneNameChange)
    @dec.getterSetter(true, true)
    public name: string = "";
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneTransformChange)
    @dec.getterSetter(true, true)
    public transform: geom.Transform = new geom.Transform();
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneParentChange)
    @dec.getterSetter(true, true)
    public parent: Bone | null = null;
    public userData: UserData | null = null;
    // 其他属性。
    // ==========================================================================================
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneVisibleChange)
    @dec.getterSetter(true, true)
    public visible: boolean = true;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneSelectableChange)
    @dec.getterSetter(true, true)
    public selectable: boolean = true;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneSelectChange)
    @dec.getterSetter(true, true)
    public selected: boolean = false;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.BoneOpenedChange)
    @dec.getterSetter(true, true)
    public opened: boolean = false;
    public armature: Armature;
}

export class Slot extends mvc.Model implements dbtps.IName {
    // 普通输出属性。
    // ==========================================================================================
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotZOrderChange)
    @dec.getterSetter(true, true)
    public zOrder: number = 0;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotDisplayIndexChange)
    @dec.getterSetter(true, true)
    public displayIndex: number = -1;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotBlendModeChange)
    @dec.getterSetter(true, true)
    public blendMode: dbtps.BlendMode = dbtps.BlendMode.Normal;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotNameChange)
    @dec.getterSetter(true, true)
    public name: string = "";
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotColorChange)
    @dec.getterSetter(true, true)
    public color: geom.ColorTransform = new geom.ColorTransform();
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotParentChange)
    @dec.getterSetter(true, true)
    public parent: Bone;
    // 其他属性。
    // ==========================================================================================
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotVisibleChange)
    @dec.getterSetter(true, true)
    public visible: boolean = true;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotSelectableChange)
    @dec.getterSetter(true, true)
    public selectable: boolean = true;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotSelectChange)
    @dec.getterSetter(true, true)
    public selected: boolean = false;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SlotOpenedChange)
    @dec.getterSetter(true, true)
    public opened: boolean = false;
    public armature: Armature;
}

export class Mesh extends mvc.Model implements dbtps.IName {
    public skinned: boolean = false;
    public name: string = "";
}

export class Skin extends mvc.Model implements dbtps.IName {
    // 普通输出属性。
    // ==========================================================================================
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.SkinNameChange)
    @dec.getterSetter(true, true)
    public name: string = "";
    public slots: SkinSlotData[] = [];
}

export class SkinSlotData extends mvc.Model implements dbtps.IName {
    // 普通输出属性。
    // ==========================================================================================
    public displays: Display[] = [];
    @dec.addHistoryAndNotification(true)
    @dec.getterSetter(true, true)
    public slot: Slot;

    public get name(): string {
        return this.slot.name;
    }
}

export abstract class Display extends mvc.Model implements dbtps.IName {
    public type: dbtps.DisplayType;
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.DisplayNameChange)
    @dec.getterSetter(true, true)
    public name: string = "";
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.DisplayTransformChange)
    @dec.getterSetter(true, true)
    public transform: geom.Transform = new geom.Transform();
}

export class TextureDisplay extends Display {
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.DisplayPivotChange)
    @dec.getterSetter(true, true)
    public pivot: geom.Point = new geom.Point(0.5, 0.5);
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.DisplayTextureChange)
    @dec.getterSetter(true, true)
    public texture: Texture;
    public constructor() {
        super();

        this.type = dbtps.DisplayType.Texture;
    }
}

export class MeshDisplay extends Display {
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.DisplayTextureChange)
    @dec.getterSetter(true, true)
    public texture: Texture;
    public mesh: Mesh;
    public constructor() {
        super();

        this.type = dbtps.DisplayType.Mesh;
    }
}

export class ArmatureDisplay extends Display {
    public actions: Action[] = [];
    @dec.addHistoryAndNotification(true, dbtps.MNotificationType.DisplayArmatureChange)
    @dec.getterSetter(true, true)
    public armature: Armature;
    public constructor() {
        super();

        this.type = dbtps.DisplayType.Armature;
    }
}

export class BoundingBoxDisplay extends Display {
    public subType: dbtps.BoundingBoxType = dbtps.BoundingBoxType.Polygon;
    public color: number = 0;
    public width: number = 0.0;
    public height: number = 0.0;
    public name: string = "";
    public vertices: number[] = [];
    public constructor() {
        super();

        this.type = dbtps.DisplayType.BoundingBox;
    }
}

export class PathDisplay extends Display {
    public constructor() {
        super();

        this.type = dbtps.DisplayType.Path;
    }
}

export class Animation extends mvc.Model implements dbtps.IName {
    //public playTimes: number = 0;
    //public scale: number = 1.0;

    public duration: number = 0.0;
    public name: string = "";
    //public action: ActionTimeline = new ActionTimeline();
    //public zOrder: ZOrderTimeline = new ZOrderTimeline();
    public timelines: Timeline<any, any>[] = [];
}

export class Timeline<F extends Frame<F>, T extends dbtps.IName> extends mvc.Model implements dbtps.IName {
    public type: dbtps.TimelineType;
    public timeScale: number = 1.0;
    public offset: number = 0.0;
    public frames: F[] = [];
    public target: T;
    public cacheFrames: F[] = [];

    public get name(): string {
        return this.target.name;
    }
}

export class AnimationTimeline extends Timeline<FloatFrame, Animation> {
}

export abstract class Frame<T> extends mvc.Model {
    public position: number = 0; // (frame)
    public duration: number = 0; // (frame)
    public prev: T;
    public next: T;
}

export abstract class TweenFrame<T> extends Frame<T> {
    public tweenType: dbtps.TweenType = dbtps.TweenType.None;
    public tweenEasing: number = 0.0;
    public curve: number[] = [];
    public cacheCurve: number[] = [];
}

export class ActionFrame extends Frame<ActionFrame> {
}

export class ZOrderFrame extends Frame<ZOrderFrame> {
}

export class IntFrame extends Frame<IntFrame>{
    public value: number = 0;
}

export class FloatFrame extends TweenFrame<FloatFrame> {
    public value: number = 0.0;
}

export class RotationFrame extends TweenFrame<RotationFrame> {
    public rotate: number = 0;
    public value: number = 0.0;
}

export class ColorTransformFrame extends TweenFrame<ColorTransformFrame> {
    public value: geom.ColorTransform = new geom.ColorTransform();
}

export class FFDFrame extends TweenFrame<FFDFrame> {
    public value: number[] = [];
}
/**
 * 动画配置。
 */
// export class AnimationConfig extends mvc.Model implements dbtps.IName {
//     public additiveBlending: boolean = false;
//     public displayControl: boolean = true;
//     public pauseFadeIn: boolean = true;
//     public actionEnabled: boolean = true;
//     public layer: number = 0;
//     public playTimes: number = 1;
//     public position: number = 0;
//     public duration: number = -1;
//     public timeScale: number = 1.0;
//     public weight: number = 1.0;
//     public fadeInTime: number = 0.0;
//     public fadeInEasing: number = 0.0;
//     public autoFadeOutTime: number = -1.0;
//     public name: string = "";
//     public group: string = "";
//     public animation: Animation;
// }